;;  Copyright (c) Jeffrey Straszheim. All rights reserved.  The use and
;;  distribution terms for this software are covered by the Eclipse Public
;;  License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
;;  be found in the file epl-v10.html at the root of this distribution.  By
;;  using this software in any fashion, you are agreeing to be bound by the
;;  terms of this license.  You must not remove this notice, or any other,
;;  from this software.
;;
;;  test-util.clj
;;
;;  A Clojure implementation of Datalog -- Utilities Tests
;;
;;  straszheimjeffrey (gmail)
;;  Created 11 Feburary 2009

(ns clojure.datalog.tests.test-util
  (:use clojure.contrib.test-is
	clojure.datalog.util)
  (:use [clojure.contrib.except :only (throwf)]))

(deftest test-is-var?
  (is (is-var? '?x))
  (is (not (is-var? 'x)))
  (is (not (is-var? "fred")))
  (is (not (is-var? :q))))

(deftest test-map-values
  (let [map {:fred 1 :sally 2}]
    (is (= (map-values #(* 2 %) map) {:fred 2 :sally 4}))
    (is (= (map-values identity {}) {}))))

(deftest test-fixed-point
  (is (= (fixed-point 99 #(quot % 2) 100) 0))
  (is (thrown-with-msg? Exception #"Fixed point overflow"
                        (fixed-point 0 #(+ 1 %) 99)))
  (is (= (fixed-point 3 #(* % 2) 99 #(mod % 6)) 12)))

;; Graphs

(def test-graph
     (struct-map directed-graph
       :nodes #{[0 [0 1]] [1 [2 3]] [1 [3 4]] [2 []] [3 [0 2]] [4 [1]]}
       :get-keys (fn [node] [(first node)])
       :get-neighbors #(frest %)))

(def empty-graph
     (struct-map directed-graph
       :nodes #{}
       :get-keys (fn [] (throwf "Get Keys Called"))
       :get-neighbors (fn [] (throwf "Get Neighbors Called"))))

(def lookup (make-lookup test-graph))

(deftest test-make-lookup
  (is (= (lookup 1) #{[1 [2 3]] [1 [3 4]]}))
  (is (= (count lookup) 5))
  (is (= (make-lookup empty-graph) {})))

(def rev-test-graph (reverse-graph test-graph))

(defn get-all-keys [{:keys [nodes get-keys]}] (map get-keys nodes))

(defn get-all-neighbors [{:keys [nodes get-neighbors]}] (map get-neighbors nodes))

(deftest test-reverse-graph
  (is (= (:nodes test-graph) (:nodes rev-test-graph)))
  (is (= (get-all-keys test-graph) (get-all-neighbors rev-test-graph)))
  (is (= (get-all-neighbors test-graph) (get-all-keys rev-test-graph))))

(deftest test-get-adjacent-nodes
  (is (= #{[0 [0 1]] [2 []]} (get-adjacent-nodes test-graph lookup [3 [0 2]])))
  (is (= #{} (get-adjacent-nodes test-graph [2 []]))))


; This isn't a comprehensive test, but if it is wrong scc, and
; recursive partition will fail.

(deftest test-post-ordered-depth-first-walk
  (is (= (set (:nodes test-graph))
         (set (post-ordered-depth-first-walk test-graph lookup ()))))
  (is (= [3 [0 2]]
           (first (post-ordered-depth-first-walk test-graph lookup ()))))
  (is (empty? (post-ordered-depth-first-walk empty-graph
                                             (make-lookup empty-graph)
                                             ()))))

(deftest test-scc
  (is (some (fn [x] (= x #{[2 []]}))
            (scc test-graph lookup)))
  (is (some (fn [x] (= x (disj (set (:nodes test-graph)) [2 []])))
            (scc test-graph lookup)))
  (is (empty (scc empty-graph (make-lookup empty-graph)))))

(deftest test-partition-into-recursive-sets
  (is (= (list (disj (set (:nodes test-graph)) [2 []]))
         (partition-into-recursive-sets test-graph lookup)))
  (is (empty? (partition-into-recursive-sets empty-graph (make-lookup empty-graph)))))

(def test-dependency-graph
     (struct-map directed-graph
       :nodes [
               {:n :b :c [:c :f] :l 0}
               {:n :c :c [:d :e] :l 0}
               {:n :d :c []      :l 0}
               {:n :f :c []      :l 0}
               {:n :e :c [:f]    :l 0}
               {:n :a :c [:b]    :l 0}
               ]
       :get-keys (fn [{:keys [n]}] [n])
       :get-neighbors (fn [{:keys [c]}] c)))

(def test-level :l)
(defn new-node
  [node nodes]
  (assoc node :l (inc (apply max -1 (map :l nodes)))))
(def dependencies (build-dependency-levels test-dependency-graph test-level new-node))
(def nodes (map :n (sort-by :l (:nodes dependencies))))
               
(deftest test-build-dependency-levels
  (is (or (= nodes (list :d :f :e :c :b :a))
          (= nodes (list :f :d :e :c :b :a))))
  (is (= empty-graph (build-dependency-levels empty-graph
                                              #(throwf "Level")
                                              #(throwf "New Node")))))

(def dep-array (build-dependency-array (:nodes dependencies) test-level))

(deftest test-dep-array
  (is (= (list 2 1 1 1 1) (map count dep-array))))


(def some-maps
     [
      { :a 1 :b 2 }
      { :c 3 :b 3 }
      { :d 4 :a 1 }
      { :g 4 :b 4 }
      { :a 2 :b 1 }
      { :e 1 :f 1 }
      ])

(def reduced (preduce + some-maps))
(def merged (apply merge-with + some-maps))

(deftest test-preduce
  (is (= reduced merged)))


; End of file
